package jp.reflexworks.invoice.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Logger;

import jp.reflexworks.invoice.model.Order;
import jp.sourceforge.reflex.util.FieldMapper;

public class OrderConverter {
	
	private Logger logger = Logger.getLogger(this.getClass().getName());
	
	//Orderの未削除フラグ
	private static final int INT_NOT_DELETED = 0;
	
	/**
	 * 一品一葉の明細からまとめ明細を生成する
	 * 
	 * List<Order> listOrderExpanded : 一品一葉明細
	 *   データストアからinvoiceNoをキーにして抽出したOrderのリスト
	 *   
	 * List<Order> listOrderReduced : まとめ明細
	 *   listOrderExpandedをproductcdをキーとして、quantity, lineTotalなどをまとめたOrderのリスト
	 * 
	 * @param List<Order> listOrderExpanded 一品一葉明細
	 * @return List<Order> listOrderReduced まとめ明細
	 */
	public List<Order> reduce(List<Order> listOrderExpanded) {

		List<Order> listOrderReduced = new ArrayList<Order>();
		Map<String, Order> mapOrderReduced = getMapOrderReduced(listOrderExpanded);
		
		//mapからlistへ
		listOrderReduced.addAll(mapOrderReduced.values());
		
		// nameの昇順でソート
		Collections.sort(listOrderReduced, new Comparator<Order>() {
			public int compare(Order ord1, Order ord2) {
				String ord1seq = ord1.getSeqno();
				String ord2seq = ord2.getSeqno();
				if (ord1seq.compareTo(ord2seq) < 0) {
					return -1;
				} else if (ord1seq.compareTo(ord2seq) > 0) {
					return 1;
				}
				return 0;
			}
		});

		return listOrderReduced;
	}
	
	/**
	 * 一品一葉レコード（OrderExpanded）から、商品コード(productcd)別のまとめレコード（OrderReduced）を求めてMapにする
	 * 
	 * @param listOrderExpanded
	 * @return
	 */
	private Map<String, Order> getMapOrderReduced(List<Order> listOrderExpanded) {
		
		Map<String, Order> mapOrderReduced = new TreeMap<String, Order>();
		
		//productcdをキーとしたOrderのmapを生成
		int seqno = 0;
		
		// 一品一葉レコード分繰り返し
		for (Order orderExpanded:listOrderExpanded) {
		
			if (orderExpanded.getDeleted() == INT_NOT_DELETED) {
				Order order;
				
				String productcd = orderExpanded.getProductcd();
				if (productcd==null) continue;
				
				int quantity = 0;
				int unitPrice = 0;
				int lineTotal = 0;
				
				if (mapOrderReduced.get(productcd) == null) {
					order = new Order();
					order.setProductcd(productcd);
				
					quantity = 1;
					try {
						unitPrice = Integer.parseInt(orderExpanded.getUnitPrice().trim().replaceAll(",",""));
					}catch(java.lang.NumberFormatException e){
						// Do nothing
					}
					lineTotal = unitPrice ;
					++seqno;
				} else {
					order = mapOrderReduced.get(productcd);
					
					quantity = Integer.parseInt(order.getQuantity().trim());
					++quantity;
					
					try {
						unitPrice = Integer.parseInt(order.getUnitPrice().trim().replaceAll(",",""));
						lineTotal = unitPrice * quantity;
						seqno = Integer.parseInt(order.getSeqno().trim());
					}catch(java.lang.NumberFormatException e){
						// Do nothing
					}
				}
				order.setQuantity(""+quantity);
				order.setUnitPrice(""+unitPrice);
				order.setLineTotal(""+lineTotal);
				order.setSeqno(""+seqno);
				order.setInvoiceNo(orderExpanded.getInvoiceNo());
				

				mapOrderReduced.put(productcd, order);
			}
		}

		return mapOrderReduced;
	}
	
	
	
	/**
	 * まとめ明細から一品一葉明細を作成する
	 * 
	 * 
	 * @param List<Order> listOrderReduced
	 * @return List<Order> listOrderExpanded
	 */
	public List<Order> expand(List<Order> listOrderReduced) {
		FieldMapper fieldMapper = new FieldMapper();
		
		List<Order> listOrderExpanded = new ArrayList<Order>();
		
		for (Order orderReduced: listOrderReduced) {
			int quantity = Integer.parseInt(orderReduced.getQuantity());
			
			//quantityがマイナス値ならdeletedに1を立てる
			int deleted = quantity < 0 ? 1 : 0;
			
			int count = quantity < 0 ? Math.abs(quantity) : quantity;
			
			for (int i = 0; i < count; i++) {
				Order orderTarget = new Order();
				
				fieldMapper.setValue(orderReduced, orderTarget);
				orderTarget.setQuantity("1");
				orderTarget.setDeleted(deleted);
				
				listOrderExpanded.add(orderTarget);
			}
		}

		return listOrderExpanded;
	}
	
	/**
	 * List<Order> listOrderにOrderを追加する 
	 * 
	 * @param listOrder
	 * @param productcd
	 * @param unitPrice
	 * @param count
	 */
	public void addOrder(List<Order> listOrder, String productcd, int unitPrice, int count) {
		int quantity = 0;
		
		for (int i = 0; i < count; i++) {
			Order o = new Order();
			o.setProductcd(productcd);
			o.setUnitPrice(""+unitPrice);
			o.setQuantity(""+quantity);
			
			listOrder.add(o);			
		}
	}
	
	
	public Map<String, Order> diff(String invoiceNo,List<Order> listSourceOrderReduced) {
		JdoUtils jdoutils = new JdoUtils();
		
		Map<String, Order> mapOrderDiff = new HashMap<String, Order>();
		
		Map<String, Order> mapTargetOrderReduced = toReducedMap(jdoutils.getOrdersByInvoiceNo(invoiceNo));
		
		for (Order sourceOrder: listSourceOrderReduced) {
			
			String productcd = sourceOrder.getProductcd();
			Order tmpOrder = new Order();
			tmpOrder.setInvoiceNo(invoiceNo);
			tmpOrder.setProductcd(productcd);
			tmpOrder.setUnitPrice(sourceOrder.getUnitPrice());		// Added by S.Takezaki
			
			int sourceQuantity =0;
			try {
				sourceQuantity = Integer.parseInt(sourceOrder.getQuantity().trim());
			} catch (Exception e) {
				continue;
			}
			if (mapTargetOrderReduced.get(productcd) == null) {
				//datastore側に存在しない
				
				//insert				
				tmpOrder.setQuantity("" + sourceQuantity);

			} else {
				//datastore側に存在する
				Order targetOrder = mapTargetOrderReduced.get(productcd);
				
				int targetQuantity = Integer.parseInt(targetOrder.getQuantity());
				
//				logger.warning("DEBUG: sourceQuantity:"+sourceQuantity+" targetQuantity:"+targetQuantity);

				tmpOrder.setQuantity("" + (sourceQuantity - targetQuantity));
			}
			
			mapOrderDiff.put(productcd, tmpOrder);
		
		}
		
		return mapOrderDiff;
	}
	
	public Map<String, Order> toReducedMap(List<Order> listOrder) {
		
		Map<String, Order> mapOrderReduced = new HashMap<String, Order>();
		
		for (Order order: listOrder) {
			
			if (order.deleted!=INT_NOT_DELETED) {
//				logger.warning("DEBUG: "+order.productcd+" deleted");
				continue;
			}
			
			String productcd = order.getProductcd();
			if (mapOrderReduced.get(productcd) == null) {
				Order tmpOrder = new Order();
				tmpOrder.setQuantity("1");
				
				mapOrderReduced.put(productcd, tmpOrder);
			} else {
				Order tmpOrder = mapOrderReduced.get(productcd);
				
				int quantity = Integer.parseInt(tmpOrder.getQuantity()) + Integer.parseInt(order.getQuantity());
				
				tmpOrder.setQuantity(""+quantity);
			}
//			logger.warning("DEBUG: "+productcd+" :"+mapOrderReduced.get(productcd).quantity);

		}
		
		
		return mapOrderReduced;
	}

	
	
	
}
